Allow disabling pulling from LAN/USB/Internet
authorMatthew Leeds <matthew.leeds@endlessm.com>
Wed, 17 Oct 2018 19:55:38 +0000 (12:55 -0700)
committerAtomic Bot <atomic-devel@projectatomic.io>
Sun, 21 Oct 2018 19:11:43 +0000 (19:11 +0000)
Currently libostree essentially has two modes when it's pulling refs:
the "legacy" code paths pull only from the Internet, and the code paths
that are aware of collection IDs try to pull from the Internet, the
local network, and mounted filesystems (such as USB drives). The problem
is that while we eventually want to migrate everyone to using collection
IDs, we don't want to force checking LAN and USB sources if the user
just wants to pull from the Internet, since the LAN/USB code paths can
have privacy[1], security[2], and performance[3] implications.

So this commit implements a new repo config option called "repo-finders"
which can be configured to, for example, "config;lan;mount;" to check
all three sources or "config;mount;" to disable searching the LAN. The
set of values mirror those used for the --finders option of the
find-remotes command. This configuration affects pulls in three places:
1. the ostree_repo_find_remotes_async() API, regardless of whether or
not the user of the API provided a list of OstreeRepoFinders
2. the ostree_repo_finder_resolve_async() /
ostree_repo_finder_resolve_all_async() API
3. the find-remotes command

This feature is especially important right now since we soon want to
have Flathub publish a metadata key which will have Flatpak clients
update the remote config to add a collection ID.[4]

This effectively fixes https://github.com/flatpak/flatpak/issues/1863
but I'll patch Flatpak too, so it doesn't pass finders to libostree only
to then have them be removed.

[1] https://github.com/flatpak/flatpak/issues/1863#issuecomment-404128824
[2] https://github.com/ostreedev/ostree/issues/1527
[3] Based on how long the "ostree find-remotes" command takes to
  complete, having the LAN finder enabled slows down that step of the
  pull process by about 40%. See also
  https://github.com/flatpak/flatpak/issues/1862
[4] https://github.com/flathub/flathub/issues/676

Closes: #1758
Approved by: cgwalters

apidoc/ostree-sections.txt
man/ostree.repo-config.xml
src/libostree/libostree-devel.sym
src/libostree/ostree-repo-private.h
src/libostree/ostree-repo-pull.c
src/libostree/ostree-repo.c
src/libostree/ostree-repo.h

index 440fe0c35a6af167a0a12d4a1f293f046b054ad2..a91663ed50faf5aed85118a29864b959f643c27f 100644 (file)
@@ -298,6 +298,7 @@ ostree_repo_get_mode
 ostree_repo_get_min_free_space_bytes
 ostree_repo_get_config
 ostree_repo_get_dfd
+ostree_repo_get_repo_finders
 ostree_repo_hash
 ostree_repo_equal
 ostree_repo_copy_config
index 8942a00bcb5e6c497a94a86bc762223d4b642ac5..49044b460696353fd75167a768e6239e263d45f1 100644 (file)
@@ -215,6 +215,20 @@ Boston, MA 02111-1307, USA.
         of -1 means block indefinitely. The default value is 30.
         </para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>repo-finders</varname></term>
+        <listitem><para>Semicolon separated default list of finders (sources
+        for refs) to use when pulling. This can be used to disable
+        pulling from mounted filesystems, peers on the local network,
+        or the Internet. However note that it only applies when a set
+        of finders isn't explicitly specified, either by a consumer of
+        libostree API or on the command line. Possible values:
+        <literal>config</literal>, <literal>lan</literal>, and
+        <literal>mount</literal> (or any combination thereof). If
+        unset, this defaults to <literal>config;lan;mount;</literal>.
+        </para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 6d1fe9346ffae218650dfc7dc556f4bf9523d9c5..80b04fd574b5ff3437e987656d7e732f6761be2a 100644 (file)
@@ -21,6 +21,7 @@
 LIBOSTREE_2018.9 {
   ostree_mutable_tree_remove;
   ostree_repo_get_min_free_space_bytes;
+  ostree_repo_get_repo_finders;
 } LIBOSTREE_2018.7;
 
 /* Stub section for the stable release *after* this development one; don't
index ad1269b3257cd4ea7382a5ab9548a64490d34081..40be72633d8905f98a351b8cf6c6f222caf1dc26 100644 (file)
@@ -168,6 +168,7 @@ struct OstreeRepo {
   gint lock_timeout_seconds;
   guint64 payload_link_threshold;
   gint fs_support_reflink; /* The underlying filesystem has support for ioctl (FICLONE..) */
+  gchar **repo_finders;
 
   OstreeRepo *parent_repo;
 };
index f5c52e4a9602b9382a05c68ae94b86b4d13bcf63..4a3adf2a6789cdd7feebf3cbd704af9867515423 100644 (file)
@@ -4999,45 +4999,55 @@ ostree_repo_find_remotes_async (OstreeRepo                     *self,
   /* Are we using #OstreeRepoFinders provided by the user, or the defaults? */
   if (finders == NULL)
     {
+      guint finder_index = 0;
 #ifdef HAVE_AVAHI
+      guint avahi_index;
       GMainContext *context = g_main_context_get_thread_default ();
       g_autoptr(GError) local_error = NULL;
 #endif  /* HAVE_AVAHI */
 
-      finder_config = OSTREE_REPO_FINDER (ostree_repo_finder_config_new ());
-      finder_mount = OSTREE_REPO_FINDER (ostree_repo_finder_mount_new (NULL));
+      if (g_strv_contains ((const char * const *)self->repo_finders, "config"))
+        default_finders[finder_index++] = finder_config = OSTREE_REPO_FINDER (ostree_repo_finder_config_new ());
+
+      if (g_strv_contains ((const char * const *)self->repo_finders, "mount"))
+        default_finders[finder_index++] = finder_mount = OSTREE_REPO_FINDER (ostree_repo_finder_mount_new (NULL));
+
 #ifdef HAVE_AVAHI
-      finder_avahi = OSTREE_REPO_FINDER (ostree_repo_finder_avahi_new (context));
+      if (g_strv_contains ((const char * const *)self->repo_finders, "lan"))
+        {
+          avahi_index = finder_index;
+          default_finders[finder_index++] = finder_avahi = OSTREE_REPO_FINDER (ostree_repo_finder_avahi_new (context));
+        }
 #endif  /* HAVE_AVAHI */
 
-      default_finders[0] = finder_config;
-      default_finders[1] = finder_mount;
-      default_finders[2] = finder_avahi;
-
+      g_assert (default_finders != NULL);
       finders = default_finders;
 
 #ifdef HAVE_AVAHI
-      ostree_repo_finder_avahi_start (OSTREE_REPO_FINDER_AVAHI (finder_avahi),
-                                      &local_error);
-
-      if (local_error != NULL)
+      if (finder_avahi != NULL)
         {
-          /* See ostree-repo-finder-avahi.c:ostree_repo_finder_avahi_start, we
-           * intentionally throw this so as to distinguish between the Avahi
-           * finder failing because the Avahi daemon wasn't running and
-           * the Avahi finder failing because of some actual error.
-           *
-           * We need to distinguish between g_debug and g_warning here because
-           * unit tests that use this code may set G_DEBUG=fatal-warnings which
-           * would cause client code to abort if a warning were emitted.
-           */
-          if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-            g_debug ("Avahi finder failed under normal operation; removing it: %s", local_error->message);
-          else
-            g_warning ("Avahi finder failed abnormally; removing it: %s", local_error->message);
+          ostree_repo_finder_avahi_start (OSTREE_REPO_FINDER_AVAHI (finder_avahi),
+                                          &local_error);
 
-          default_finders[2] = NULL;
-          g_clear_object (&finder_avahi);
+          if (local_error != NULL)
+            {
+              /* See ostree-repo-finder-avahi.c:ostree_repo_finder_avahi_start, we
+               * intentionally throw this so as to distinguish between the Avahi
+               * finder failing because the Avahi daemon wasn't running and
+               * the Avahi finder failing because of some actual error.
+               *
+               * We need to distinguish between g_debug and g_warning here because
+               * unit tests that use this code may set G_DEBUG=fatal-warnings which
+               * would cause client code to abort if a warning were emitted.
+               */
+              if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+                g_debug ("Avahi finder failed under normal operation; removing it: %s", local_error->message);
+              else
+                g_warning ("Avahi finder failed abnormally; removing it: %s", local_error->message);
+
+              default_finders[avahi_index] = NULL;
+              g_clear_object (&finder_avahi);
+            }
         }
 #endif  /* HAVE_AVAHI */
     }
index 857b2d4ccc8fa1ec4016cbde2255c31947753ff1..18fb7733d5ede6ca36c97ce38bd7c090aa9da8cb 100644 (file)
@@ -1035,6 +1035,7 @@ ostree_repo_finalize (GObject *object)
   g_mutex_clear (&self->cache_lock);
   g_mutex_clear (&self->txn_lock);
   g_free (self->collection_id);
+  g_strfreev (self->repo_finders);
 
   g_clear_pointer (&self->remotes, g_hash_table_destroy);
   g_mutex_clear (&self->remotes_lock);
@@ -2938,6 +2939,40 @@ reload_core_config (OstreeRepo          *self,
     self->payload_link_threshold = g_ascii_strtoull (payload_threshold, NULL, 10);
   }
 
+  { g_auto(GStrv) configured_finders = NULL;
+    g_autoptr(GError) local_error = NULL;
+
+    configured_finders = g_key_file_get_string_list (self->config, "core", "repo-finders",
+                                                     NULL, &local_error);
+    if (g_error_matches (local_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
+      g_clear_error (&local_error);
+    else if (local_error != NULL)
+      {
+        g_propagate_error (error, g_steal_pointer (&local_error));
+        return FALSE;
+      }
+
+    if (configured_finders != NULL && *configured_finders == NULL)
+      return glnx_throw (error, "Invalid empty repo-finders configuration");
+
+    for (char **iter = configured_finders; iter && *iter; iter++)
+      {
+        const char *repo_finder = *iter;
+
+        if (strcmp (repo_finder, "config") != 0 &&
+            strcmp (repo_finder, "lan") != 0 &&
+            strcmp (repo_finder, "mount") != 0)
+          return glnx_throw (error, "Invalid configured repo-finder '%s'", repo_finder);
+      }
+
+    /* Fall back to a default set of finders */
+    if (configured_finders == NULL)
+      configured_finders = g_strsplit ("config;lan;mount", ";", -1);
+
+    g_clear_pointer (&self->repo_finders, g_strfreev);
+    self->repo_finders = g_steal_pointer (&configured_finders);
+  }
+
   return TRUE;
 }
 
@@ -5915,3 +5950,22 @@ ostree_repo_set_collection_id (OstreeRepo   *self,
 
   return TRUE;
 }
+
+/**
+ * ostree_repo_get_repo_finders:
+ * @self: an #OstreeRepo
+ *
+ * Get the set of repo finders configured. See the documentation for
+ * the "core.repo-finders" config key.
+ *
+ * Returns: (array zero-terminated=1) (element-type utf8):
+ *    %NULL-terminated array of strings.
+ * Since: 2018.9
+ */
+const gchar * const *
+ostree_repo_get_repo_finders (OstreeRepo *self)
+{
+  g_return_val_if_fail (OSTREE_IS_REPO (self), NULL);
+
+  return (const gchar * const *)self->repo_finders;
+}
index eddbbf87012d2df743e95be76d206e988345ba91..2f7abf6d1c179a1898836a9cc2b85a0ae4b7d8a7 100644 (file)
@@ -112,6 +112,9 @@ gboolean      ostree_repo_set_collection_id (OstreeRepo   *self,
                                              const gchar  *collection_id,
                                              GError      **error);
 
+_OSTREE_PUBLIC
+const gchar * const * ostree_repo_get_repo_finders (OstreeRepo   *self);
+
 _OSTREE_PUBLIC
 GFile *       ostree_repo_get_path (OstreeRepo  *self);